package com.tsd.jxc.stock.service.impl;

import com.tsd.base.service.BaseCodeRuleService;
import com.tsd.common.vo.BatchDeleteLogicVo;
import com.tsd.core.constants.Constants;
import com.tsd.core.service.GetDuplicatedObj;
import com.tsd.core.thread.ThreadPoolTaskUtil;
import com.tsd.core.utils.DateUtil;
import com.tsd.core.utils.DoubleUtil;
import com.tsd.core.utils.HlpUtils;
import com.tsd.core.utils.ListUtil;
import com.tsd.core.vo.HlpException;
import com.tsd.core.vo.PageBean;
import com.tsd.jxc.buy.dao.JxcBuyReturnBillDetailMapper;
import com.tsd.jxc.buy.dao.JxcBuyReturnBillMapper;
import com.tsd.jxc.config.JxcCodeRuleConstants;
import com.tsd.jxc.sale.dao.JxcSaleOrderDetailMapper;
import com.tsd.jxc.sale.dao.JxcSaleOrderMapper;
import com.tsd.jxc.stock.StockConstants;
import com.tsd.jxc.stock.dao.JxcStockOutbillItemMapper;
import com.tsd.jxc.stock.dao.JxcStockOutbillMapper;
import com.tsd.jxc.stock.entity.JxcStockOutbill;
import com.tsd.jxc.stock.entity.JxcStockOutbillExt;
import com.tsd.jxc.stock.entity.JxcStockOutbillItemExt;
import com.tsd.jxc.stock.job.JxcStockJob;
import com.tsd.jxc.stock.service.JxcStockOutbillItemService;
import com.tsd.jxc.stock.service.JxcStockOutbillService;
import com.tsd.jxc.utils.JxcUtils;
import com.tsd.service.BaseServiceImpl;
import com.tsd.system.entity.SysUser;
import com.tsd.system.entity.SysUserExt;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 描述：JxcStockOutbill 服务实现层
 *
 * @author Hillpool
 * @date 2022/07/29 15:06:33
 */
@Service
public class JxcStockOutbillServiceImpl extends BaseServiceImpl implements JxcStockOutbillService, GetDuplicatedObj {

    @Resource
    private JxcStockOutbillMapper jxcStockOutbillMapper;
    @Resource
    private JxcStockOutbillItemMapper jxcStockOutbillItemMapper;
    @Resource
    private JxcSaleOrderMapper jxcSaleOrderMapper;
    @Resource
    private JxcSaleOrderDetailMapper jxcSaleOrderDetailMapper;
    @Resource
    private JxcBuyReturnBillMapper jxcBuyReturnBillMapper;
    @Resource
    private JxcBuyReturnBillDetailMapper jxcBuyReturnBillDetailMapper;
    @Resource
    private BaseCodeRuleService baseCodeRuleService;
    @Resource
    private JxcStockOutbillItemService jxcStockOutbillItemService;
    @Resource
    private JxcStockJob jxcStockJob;

    @Override
    public JxcStockOutbill getJxcStockOutbillById(Long id) throws Exception {
        return jxcStockOutbillMapper.selectByPrimaryKey(id);
    }

    @Override
    public JxcStockOutbillExt queryBySid(String sid) throws Exception {
        JxcStockOutbillExt billExt = jxcStockOutbillMapper.selectBySid(sid);
        if (billExt != null) {
            List<JxcStockOutbillItemExt> itemExtList = jxcStockOutbillItemService.queryValidByBillList(Collections.singletonList(sid));
            billExt.setItem_list(itemExtList);
        }
        return billExt;
    }

    @Override
    public void deleteJxcStockOutbills(List<String> list, SysUser opUser) throws Exception {
        if (HlpUtils.isEmptyList(list)) {
            return;
        }
        BatchDeleteLogicVo logicVo = new BatchDeleteLogicVo(opUser);
        logicVo.setSidList(list);
        jxcStockOutbillMapper.deleteLogicBySidList(logicVo);
        // 删除明细
        jxcStockOutbillItemMapper.deleteLogicByBillList(logicVo);

        // 还原单据“生成出库单”
        jxcSaleOrderDetailMapper.restoreOutBill(list);
        jxcSaleOrderMapper.restoreOutBill(list);
        jxcBuyReturnBillDetailMapper.restoreOutBill(list);
        jxcBuyReturnBillMapper.restoreOutBill(list);
    }

    @Override
    public boolean isDuplicated(Object obj, String code) {
        if (obj == null) {
            return false;
        }
        JxcStockOutbillExt billExt = (JxcStockOutbillExt) obj;
        billExt.setCode(code);
        return jxcStockOutbillMapper.selectDuplicatedCode(billExt) != null;
    }

    @Override
    public void saveJxcStockOutbill(JxcStockOutbillExt record, SysUser opUser) throws Exception {
        if (HlpUtils.isEmpty(record.getId())) {
            if (!HlpUtils.isEmpty(record.getCode())) {
                //如果是手动设置了编号，则检查是否有相同的，有的话，置空后重新生成
                JxcStockOutbillExt same = jxcStockOutbillMapper.selectDuplicatedCode(record);
                if (same != null) {
                    record.setCode(null);
                }
            }
            String genCode = baseCodeRuleService.genCode(null, JxcCodeRuleConstants.TYPE_JXC_OUT_BILL, JxcCodeRuleConstants.TYPE_NAME_JXC_OUT_BILL, opUser, record.getCode(), record, this);
            record.setCode(genCode);
            if (HlpUtils.isEmpty(record.getAudit_state())) {
                record.setAudit_state(Constants.VALUE_NO);
            }
            if (HlpUtils.isEmpty(record.getExecute_state())) {
                record.setExecute_state(Constants.VALUE_NO);
            }
            super.autoInjectBaseData(record, opUser, this.TYPE_CREATE, new Date(), record.getOut_date());
            jxcStockOutbillMapper.insertSelective(record);
        } else {
            JxcStockOutbillExt same = jxcStockOutbillMapper.selectDuplicatedCode(record);
            if (same != null) {
                throw new HlpException("已存在相同编号的记录");
            }
            super.autoInjectBaseData(record, opUser, this.TYPE_UPDATE);
            super.updateYyyyMmdd(record, record.getOut_date());
            jxcStockOutbillMapper.updateByPrimaryKeySelective(record);
        }
        jxcStockOutbillItemService.saveJxcStockOutbillItem(record, opUser);
    }

    @Override
    public List<JxcStockOutbillExt> findJxcStockOutbills(Map<String, Object> params, PageBean page) throws Exception {
        if (params.containsKey("goods_name")) {
            String goods_name = HlpUtils.getString(params, "goods_name");
            List<JxcStockOutbillItemExt> list = jxcStockOutbillItemMapper.selectByGoodsName(goods_name);
            if (list == null || list.isEmpty()) {
                return null;
            }
            List<String> outBillSids = ListUtil.map(list, JxcStockOutbillItemExt::getOutbill_sid).stream().distinct().collect(Collectors.toList());
            params.put("outBillSids", outBillSids);
        }
        return jxcStockOutbillMapper.selectByPage(params, page);
    }

    @Override
    public List<JxcStockOutbillExt> findJxcStockOutbills(Map<String, Object> params) throws Exception {
        return jxcStockOutbillMapper.selectByParams(params);
    }

    @Override
    public void changeJxcStockOutBillAuditState(List<String> sidList, Integer state, SysUserExt opUser) throws Exception {
        JxcStockOutbillExt params = new JxcStockOutbillExt();
        params.setDr(0);
        params.setSid_list(sidList);
        List<JxcStockOutbillExt> billExtList = jxcStockOutbillMapper.selectByEntity(params);
        if (HlpUtils.isEmptyList(billExtList)) {
            return;
        }
        // 检查是否已生成对账单
        if (JxcUtils.isGenReconciliationByStockBill()) {
            List<JxcStockOutbillExt> filter = ListUtil.filter(billExtList, t -> !HlpUtils.isEmpty(t.getPay_req_state()) && Constants.VALUE_NO != t.getPay_req_state());
            if (!HlpUtils.isEmptyList(filter)) {
                List<String> codeList = ListUtil.map(filter, JxcStockOutbillExt::getCode);
                String msg = "出库单：" + StringUtils.join(codeList, "、") + " 已生成对账单，无法" + (Constants.VALUE_YES == state ? "审核" : "反审");
                throw new HlpException(msg);
            }
        }
        // 审核时检查是否选择了仓位：1、获取单据；2、获取单据明细；3、检查单据明细是否选择仓位；4、检查单据明细仓位的数量与单据明细数量是否一致
        StringBuilder builder = new StringBuilder();
        List<String> outBillSids = ListUtil.map(billExtList, JxcStockOutbillExt::getSid);
        List<JxcStockOutbillItemExt> itemExtList = jxcStockOutbillItemMapper.selectBySids(outBillSids, 0);
        if (itemExtList == null || itemExtList.isEmpty()) {
            return;
        }
        List<String> outBillItemSids = ListUtil.map(itemExtList, JxcStockOutbillItemExt::getSid);
        // 遍历单据
        for (JxcStockOutbillExt outbillExt : billExtList) {
            // 获取单据明细
            List<JxcStockOutbillItemExt> filterItemList = ListUtil.filter(itemExtList, t -> outbillExt.getSid().equals(t.getOutbill_sid()));
            // 遍历单据明细
        }
        if (builder.length() > 0) {
            throw new HlpException(builder.toString());
        }

        // 审核时检查待出库数量与出库数量是否一致
        if (state == 1) {
            JxcStockOutbillItemExt checkData = jxcStockOutbillItemMapper.select4CheckPosition(sidList);
            if (checkData != null) {
                String errMsg = "出库单：" + checkData.getBill_code() + " 商品【" + checkData.getGoods_name();
                if (!HlpUtils.isEmpty(checkData.getSpec_name())) {
                    errMsg += "(" + checkData.getSpec_name() + ")";
                }
                errMsg += "】待出库数量与库存位置数量不一致";
                throw new HlpException(errMsg);
            }
        }

        for (JxcStockOutbillExt billExt : billExtList) {
            if (state == 1) {
                billExt.setAudit_state(StockConstants.STATE_AUDITED);
                billExt.setAuditor_sid(opUser.getSid());
                billExt.setAuditor_name(opUser.getName());
                billExt.setAudit_date(new Date());
            } else if (state == -1) {
                billExt.setAudit_state(StockConstants.STATE_UN_AUDIT);
                billExt.setAuditor_sid(null);
                billExt.setAuditor_name(null);
                billExt.setAudit_date(null);
            }
            super.autoInjectBaseData(billExt, opUser, this.TYPE_UPDATE);
            jxcStockOutbillMapper.updateByPrimaryKeySelective(billExt);
        }

        // 加入队列：更新 jxc_stock_goods_position 等待出库数量
        String code = state == 1 ? StockConstants.OPERATE_ADD : StockConstants.OPERATE_SUB;
        for (JxcStockOutbillExt billExt : billExtList) {
            jxcStockJob.addJxcStockQue(code, StockConstants.BIZ_NAME_OUT_BILL, "updateStockQtyOuting2StockGoodsPosition", billExt.getId(), opUser);
        }
    }

    @Override
    public void executeJxcStockOutbill(List<String> sidList, SysUserExt opUser) throws Exception {
        JxcStockOutbillExt params = new JxcStockOutbillExt();
        params.setDr(0);
        params.setSid_list(sidList);
        List<JxcStockOutbillExt> billExtList = jxcStockOutbillMapper.selectByEntity(params);
        if (HlpUtils.isEmptyList(billExtList)) {
            return;
        }

        List<JxcStockOutbillExt> filterNoAuditList = ListUtil.filter(billExtList, t -> t.getAudit_state() == Constants.VALUE_NO);
        if (!HlpUtils.isEmptyList(filterNoAuditList)) {
            List<String> codeList = ListUtil.map(filterNoAuditList, JxcStockOutbillExt::getCode);
            throw new HlpException(String.format("出库单：%s 未审核，无法执行出库操作", StringUtils.join(codeList, "、")));
        }
        List<JxcStockOutbillExt> filterExecutedList = ListUtil.filter(billExtList, t -> t.getExecute_state() == Constants.VALUE_YES);
        if (!HlpUtils.isEmptyList(filterExecutedList)) {
            List<String> codeList = ListUtil.map(filterExecutedList, JxcStockOutbillExt::getCode);
            throw new HlpException(String.format("出库单：%s 已出库", StringUtils.join(codeList, "、")));
        }

        Date now = new Date();
        for (JxcStockOutbillExt billExt : billExtList) {
            super.autoInjectBaseData(billExt, opUser, this.TYPE_UPDATE);
            billExt.setExecute_state(Constants.VALUE_YES);
            billExt.setExecute_date(now);
            billExt.setExecutor_sid(opUser.getSid());
            billExt.setExecutor_name(opUser.getName());
            billExt.setOut_yyyy(DateUtil.getYyyy(now));
            billExt.setOut_yyyymm(DateUtil.getYyyyMM(now));
            billExt.setOut_yyyymmdd(DateUtil.getYyyyMMdd(now));
            jxcStockOutbillMapper.updateByPrimaryKeySelective(billExt);
        }

        // 加入队列：更新 jxc_stock_goods_position 库存数量
        for (JxcStockOutbillExt billExt : billExtList) {
            jxcStockJob.addJxcStockQue(StockConstants.OPERATE_SUB, StockConstants.BIZ_NAME_OUT_BILL, "updateStockQty2StockGoodsPosition", billExt.getId(), opUser);
        }
    }

    @Override
    public List<JxcStockOutbillExt> findJxcStockOutbillsIncludeDetail(Map<String, Object> params, PageBean page) {
        return jxcStockOutbillMapper.selectStockOutbillsIncludeDetailByPage(params, page);
    }

    @Override
    public JxcStockOutbillExt findJxcStockOutbillsDetailPositionBySid(String sid) throws Exception {
        if (HlpUtils.isEmpty(sid)) {
            throw new HlpException("出库单sid不能为空！");
        }
        JxcStockOutbillExt jxcStockOutbillExt = jxcStockOutbillMapper.selectBySid(sid);
        if (jxcStockOutbillExt == null) {
            throw new HlpException("找不到sid（" + sid + "）的出库单记录！");
        }
        List<JxcStockOutbillItemExt> list = jxcStockOutbillItemMapper.selectStockOutbillsDetailPositionBySid(sid, 0);
        jxcStockOutbillExt.setItem_list(list);
        return jxcStockOutbillExt;
    }

    @Override
    public List<JxcStockOutbillExt> queryJxcStockOutBillData4Print(List<String> sidList) throws Exception {
        List<JxcStockOutbillExt> list = ThreadPoolTaskUtil.queryInList4Split(sidList, itemList -> {
            JxcStockOutbillExt params = new JxcStockOutbillExt();
            params.setDr(0);
            params.setSid_list(itemList);
            return jxcStockOutbillMapper.selectByEntity(params);
        });
        if (!HlpUtils.isEmptyList(list)) {
            List<String> billList = ListUtil.map(list, JxcStockOutbillExt::getSid);
            List<JxcStockOutbillItemExt> itemExtList = jxcStockOutbillItemService.queryValidByBillList(billList);
            for (JxcStockOutbillExt billExt : list) {
                List<JxcStockOutbillItemExt> filterList = ListUtil.filter(itemExtList, t -> t.getOutbill_sid().equals(billExt.getSid()));
                billExt.setItem_list(filterList);
            }
        }
        return list;
    }

    @Override
    public List<JxcStockOutbillExt> queryBySrcSid(List<String> list, int dr) {
        return jxcStockOutbillMapper.selectBySrcSid(list, dr);
    }

    @Override
    public void cancelExecuteJxcStockOutbill(List<String> sidList, SysUserExt opUser) throws Exception {
        JxcStockOutbillExt params = new JxcStockOutbillExt();
        params.setDr(0);
        params.setSid_list(sidList);
        List<JxcStockOutbillExt> billExtList = jxcStockOutbillMapper.selectByEntity(params);
        if (HlpUtils.isEmptyList(billExtList)) {
            return;
        }

        List<JxcStockOutbillExt> filterExecutedList = ListUtil.filter(billExtList, t -> t.getExecute_state() == Constants.VALUE_NO);
        if (!HlpUtils.isEmptyList(filterExecutedList)) {
            List<String> codeList = ListUtil.map(filterExecutedList, JxcStockOutbillExt::getCode);
            throw new HlpException(String.format("出库单：%s 未出库", StringUtils.join(codeList, "、")));
        }

        for (JxcStockOutbillExt billExt : billExtList) {
            super.autoInjectBaseData(billExt, opUser, this.TYPE_UPDATE);
            billExt.setExecute_state(Constants.VALUE_NO);
            billExt.setExecute_date(null);
            billExt.setExecutor_sid(null);
            billExt.setExecutor_name(null);
            billExt.setOut_yyyy(null);
            billExt.setOut_yyyymm(null);
            billExt.setOut_yyyymmdd(null);
            jxcStockOutbillMapper.updateByPrimaryKey(billExt);
        }

        // 加入队列：更新 jxc_stock_goods_position 库存数量
        for (JxcStockOutbillExt billExt : billExtList) {
            jxcStockJob.addJxcStockQue(StockConstants.OPERATE_ADD, StockConstants.BIZ_NAME_OUT_BILL, "updateStockQty2StockGoodsPosition", billExt.getId(), opUser);
        }
    }
}
